package com.xdf.whiteaccount.aop;

import com.xdf.whiteaccount.dao.MaterialOrderMapper;
import com.xdf.whiteaccount.entity.BillType;
import com.xdf.whiteaccount.entity.MaterialOrder;
import com.xdf.whiteaccount.enums.ResponseEnum;
import com.xdf.whiteaccount.service.BillTypeService;
import com.xdf.whiteaccount.service.CallService;
import com.xdf.whiteaccount.utils.CalculateUtil;
import com.xdf.whiteaccount.utils.Example;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @program: white-account
 * @description: 材料单据
 * @author: 张柯
 * @create: 2021-05-26 10:19
 **/
@Component
@Slf4j
@Aspect
public class MaterialOrderServiceAspect extends AbstractAop {
    @Autowired
    private CallService callService;
    @Autowired
    private BillTypeService billTypeService;
    @Autowired
    private MaterialOrderMapper dao;

    @Pointcut("execution(* com.xdf.whiteaccount.service.MaterialOrderService.insert*(..))")
    public void cutInsert() {
    }

    @Pointcut("execution(* com.xdf.whiteaccount.service.MaterialOrderService.*pdate*(..))")
    public void cutUpdate() {
    }

    @Pointcut("execution(* com.xdf.whiteaccount.service.MaterialOrderService.cancelByPrimaryKey(..))")
    public void cutCancelByPk() {
    }

    /**
     * 插入事件
     *
     * @param joinPoint
     */
    @Before("cutInsert()")
    @Transactional(rollbackFor = Exception.class)
    public void beforeInsert(JoinPoint joinPoint) throws Exception {
        Object param = getParam1(joinPoint);
        Assert.notNull(param, ResponseEnum.NOT_ALLOW_EMPTY_DATA.getName());
        if (param instanceof MaterialOrder) {
            MaterialOrder materialOrder = (MaterialOrder) param;
            Assert.state(StringUtils.isNotEmpty(materialOrder.getBillType()), "单据类型不能为空！");
            BillType billType = billTypeService.selectByPrimaryKey(materialOrder.getBillType());
            Assert.notNull(billType, "单据编号不存在！");
            materialOrder.setCreateUserId(getLoginUserId());
            materialOrder.setCreateTime(new Date());
            materialOrder.setUpload(0);
            materialOrder.setId(null);
            boolean isSendDirectly = Optional.ofNullable(materialOrder).map(MaterialOrder::getIsSendDirectly).orElse(false);
            if (isSendDirectly) {
                Assert.state(StringUtils.isNotEmpty(materialOrder.getProcessCompany()), "直发加工户必须输入！");
            }
            //  计算金额
            materialOrder.setInputMoney(CalculateUtil.mul(materialOrder.getInputKilo(), materialOrder.getPrice()));
            materialOrder.setIsSendDirectly(isSendDirectly);
            //  根据单据类型生成不同的单据编号
            materialOrder.setOrderCode(callService.materialOrderCodeGen(billType.getAccessMode()));
        }
    }

    /**
     * 更改前事件,修改更改字段
     *
     * @param joinPoint
     */
    @Before("cutUpdate()")
    @Transactional(rollbackFor = Exception.class)
    public void beforeUpdate(JoinPoint joinPoint) throws Exception {
        Object param = getParam1(joinPoint);
        Assert.notNull(param, ResponseEnum.NOT_ALLOW_EMPTY_DATA.getName());
        if (param instanceof MaterialOrder) {
            MaterialOrder record = (MaterialOrder) param;
            MaterialOrder source = dao.selectByPrimaryKey(record.getId());
            Assert.state(!Optional.ofNullable(source).map(MaterialOrder::getIsAudit).orElse(false), ResponseEnum.IS_AUDIT.getName());
            modifyMirror(source, record);
        } else if (param instanceof List) {
            for (Object o : (List) param) {
                if (o instanceof MaterialOrder) {
                    MaterialOrder record = (MaterialOrder) o;
                    record.setUpload(0);
                    MaterialOrder source = dao.selectByPrimaryKey(record.getId());
                    modifyMirror(source, record);
                }
            }
        }
    }

    /**
     * 作废方法
     *
     * @param joinPoint
     */
    @Before("cutCancelByPk()")
    @Transactional(rollbackFor = Exception.class)
    public void beforeCancelByPk(JoinPoint joinPoint) {
        Object param = getParam1(joinPoint);
        if (param instanceof Long) {
            Long pk = (Long) param;
            MaterialOrder record = dao.selectByPrimaryKey(pk);
            Assert.state(!Optional.ofNullable(record).map(MaterialOrder::getIsAudit).orElse(false), ResponseEnum.IS_AUDIT.getName());
            Assert.state(record != null, ResponseEnum.CANCEL_ORDER.getName());
            if (StringUtils.isEmpty(record.getLinkedOrderCode())) {
                dao.updateByExampleSelective(MaterialOrder.builder().state(0).build(),
                        new Example().andEq("linked_order_code", record.getOrderCode()));
            } else {
                dao.updateByExampleSelective(MaterialOrder.builder().state(0).build(),
                        new Example().andEq("order_code", record.getLinkedOrderCode()));
            }
        }
    }

    /**
     * 更改对应的单据
     *
     * @param source
     * @param record
     * @throws Exception
     */
    private void modifyMirror(MaterialOrder source, MaterialOrder record) throws Exception {
        record.setUpload(0);
        record.setIsSendDirectly(source.getIsSendDirectly() != null && source.getIsSendDirectly());
        if (record.getIsSendDirectly()) {
            //  同时更改关联的单据
            MaterialOrder copy = (MaterialOrder) record.clone();
            copy.setId(null);
            copy.setOrderCode(null);
            copy.setLinkedOrderCode(null);
            copy.setUpload(0);
            copy.setBillType(null);
            copy.setState(null);
            String linkOrderCode;
            if (StringUtils.isEmpty(source.getLinkedOrderCode())) {
                linkOrderCode = source.getOrderCode();
            } else {
                linkOrderCode = source.getLinkedOrderCode();
            }
            dao.updateByExampleSelective(copy, new Example().andEq("linked_order_code", linkOrderCode));
        } else {
            //  计算金额
            record.setInputMoney(CalculateUtil.mul(record.getInputKilo(), record.getPrice()));
        }
    }
}